<?php

/**
 * 上传类
 */
class Upload {

    protected static $_instance = null;
    public $files = array();
    public $options = array('maxsize' => 102400000, 'suffix' => '.jpg,.rar,.txt,.zip,.gif', 'directory' => BASE_PATH . "/tmp", 'overwrite' => true);

    function __construct() {
        if (Yaf_Registry::get("config")->upload) {
            $this->options = array_merge($this->options, Yaf_Registry::get("config")->upload->toArray());
        }
    }

    public static function getInstance() {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    /**
     * 上传文件
     * @param string $name 表单中的文件名称
     * @param string $newname 新文件名称，默认为null，即不改变文件名
     * @param bool $overwrite 是否覆盖已经存在的文件，默认为false，即不覆盖
     * @param string $suffix 允许上传的文件后缀，默认为null，根据常量设置
     * @param int $maxsize 最大允许上传的大小，默认为null，根据常量设置
     * @param string $directory 上传到的文件夹，默认为null，根据常量设置
     * @return bool
     */
    public function doupload($name, $newname = null, $overwrite = false, $suffix = null, $maxsize = null, $directory = null) {
        if (isset($_FILES[$name])) {
            $this->files[$name] = $_FILES[$name];
        } else {
            $this->set_error($name, 9, '表单中不存在上传的文件名');
            return false;
        }

        //判断是否选择了文件
        if ($this->files[$name]['name'] == '') {
            $this->set_error($name, 10, '未选择上传的文件');
            return false;
        }

        //获取上传文件的信息
        preg_match("/\.([^\.]+)$/i", $this->files[$name]['name'], $extension);
        $this->files[$name]['extension'] = '.' . strtolower($extension[1]);

        //构造上传文件名
        if ($newname && !is_null($newname)) {
            $this->files[$name]['newname'] = (substr($newname, -strlen($this->files[$name]['extension']), strlen($this->files[$name]['extension'])) != $this->files[$name]['extension']) ? $newname . $this->files[$name]['extension'] : $newname;
        } else {
            $this->files[$name]['newname'] = $this->files[$name]['name'];
        }

        $this->files[$name]['suffix'] = $suffix && is_string($suffix) ? $suffix : $this->options['suffix'];
        $this->files[$name]['maxsize'] = $maxsize && is_numeric($maxsize) ? intval($maxsize) : intval($this->options['maxsize']);
        $this->files[$name]['directory'] = $directory && is_string($directory) ? $directory : $this->options['directory'];
        $this->files[$name]['overwrite'] = $overwrite ? true : false;
        //判断文件大小是否超过限制
        if ($this->files[$name]['size'] > $this->files[$name]['maxsize']) {
            $this->set_error($name, 11, '上传的文件超过指定大小');
            return false;
        }
        //判断文件类型是否允许
        if ($this->files[$name]['suffix'] != '*' && !in_array($this->files[$name]['extension'], explode(',', $this->files[$name]['suffix']))) {
            $this->set_error($name, 12, '不允许上传的文件类型');
            return false;
        }
        //构造返回的URL和上传的文件路径
        $this->files[$name]['directory'] .= ( substr($this->files[$name]['directory'], -1) != '/' || substr($this->files[$name]['directory'], -1) != '\\') ? '/' : '';
        $this->files[$name]['basepath'] = $this->files[$name]['directory'];

        //创建目录
        //mkdir($this->files[$name]['basepath']);
        if (!is_readable($this->files[$name]['basepath'])) {
            $this->set_error($name, 13, '上传目录不可写');
            return false;
        }

        $this->files[$name]['path'] = $this->files[$name]['basepath'] . $this->files[$name]['newname'];
        //判断是否存在相同文件名文件
        if (file_exists($this->files[$name]['path'])) {
            //如果为覆盖模式，则删除已经存在的文件，反之上传失败
            if ($this->files[$name]['overwrite']) {
                @unlink($this->files[$name]['path']);
            } else {
                $this->set_error($name, 14, '文件已经存在');
                return false;
            }
        }
        //开始上传
        if (!move_uploaded_file($this->files[$name]['tmp_name'], iconv('utf-8', 'gbk', $this->files[$name]['path']))) {
            $this->set_error($name, 15, '上传文件失败');
            return false;
        } else {
            @unlink($this->files[$name]['tmp_name']);
            $this->set_error($name, 0, '上传文件成功');
            return true;
        }
    }

    /**
     * 获取上传数据
     * @return array 返回上传的数据信息
     */
    function data() {
        $temp = array();
        foreach ($this->files as $key => $value) {
            unset($value['basepath'], $value['path'], $value['tmp_name']);
            $temp[$key] = $value;
        }
        return $temp;
    }

    /**
     * 设置错误信息
     * @param name $name 上传文件名称
     * @param int $id 错误代号
     * @param string $msg 错误信息
     */
    function set_error($name, $id, $msg) {
        $this->files[$name]['error'] = $id;
        $this->files[$name]['errorinfo'] = $msg;
    }

}
